package com.archtecture.control.facedes;

import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import com.archtecture.control.enums.Mensagem;
import com.archtecture.control.exceptions.NegocioException;
import com.archtecture.control.models.ModelAb;
import com.archtecture.control.util.JPQLFactory;

@Stateless(name = "PersistenceFacade")
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class PersistenceFacade implements PersistenceFacadeRemote {

	@PersistenceContext(unitName = "SPGF_PU")
	EntityManager	manager;

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model atualizar(Model pModel) throws NegocioException {

		if (pModel.getCodigo() == null) {
			throw new NegocioException(Mensagem.ERRO_ENTIDADE_SEM_CODIGO);
		}

		manager.merge(pModel);
		manager.flush();
		return pModel;
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model carregar(Model pModel) throws NegocioException {
		String jpqlString = JPQLFactory.montarConsultaJPQLResultadoUnico(pModel);
		Query query = manager.createQuery(jpqlString);
		Model model = (Model) query.getSingleResult();
		return model;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> void excluir(Model pModel) throws NegocioException {

		try {
			manager.remove(manager.find(pModel.getClass(), pModel.getCodigo()));
			manager.flush();
		} catch (PersistenceException pex) {
			pex.printStackTrace();
		}
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model inserir(Model pModel) throws NegocioException {

		if (pModel.getCodigo() != null) {
			throw new NegocioException(Mensagem.ERRO_ENTIDADE_COM_CODIGO);
		}

		try {
			manager.persist(pModel);
			manager.flush();
		} catch (Exception e) {
			throw new NegocioException(Mensagem.ERRO_GERAL, e);
		}
		return pModel;
	}

	@Override
	public <Model extends ModelAb> List<Model> pesquisarLista(Model pModel) throws NegocioException {
		String jpqlString = JPQLFactory.montarConsultaJPQLMultiplosResultados(pModel);
		return executarJPQLResultadoMultiplo(jpqlString);
	}

	@Override
	public <Model extends ModelAb> Model pesquisarUnico(Model pModel) throws NegocioException {
		String jpqlString = JPQLFactory.montarConsultaJPQLMultiplosResultados(pModel);
		return executarJPQLResultadoUnico(jpqlString);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <Model> List<Model> executarJPQLResultadoMultiplo(String jpql) {
		Query query = manager.createQuery(jpql);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <Model> Model executarJPQLResultadoUnico(String jpql) throws NegocioException {
		Query query = manager.createQuery(jpql);

		List<Model> models = query.getResultList();

		if (models.size() > 1) {
			throw new NegocioException(Mensagem.ERRO_MULTIPLOS_RESULTADOS_NA_PESQUISA_UNICA);
		}

		for (Model model : models) {
			return model;
		}

		return null;
	}
}